home *** CD-ROM | disk | FTP | other *** search
/ Programming Sound Cards / Programming Sound Cards.iso / sound_56 / dmastep3.asm < prev    next >
Assembly Source File  |  1995-01-01  |  15KB  |  377 lines

  1. ;══════════════════════════════════════════════════════════════════════════════
  2. ; Play 8bit DMA mode for SoundBlaster v1.00
  3. ;   André Baresel (with some help from Craig Jackson)
  4. ;──────────────────────────────────────────────────────────────────────────────
  5. ; Requirements: 80286, DOS 1.0, SoundBlaster (see BASEADDR,DMA channel,IRQ number)
  6. ; Resolutions : 8-bit / 4..23khz (no highspeed - but on SB16 4..44kHz)
  7. ; Parameters  : none
  8. ; Notes:
  9. ;  ■ To creat a 8 bit mono unsigned file do :   "VOC2RAW TEST1.VOC /I"
  10. ;
  11. ; ■ DSP command 48h  ... set DMA block size
  12. ; ■ DSP command 1Ch  ... play 8bit mono autoinit
  13. ; ■ DSP command 40h  ... set sample rate
  14. ; ■ DSP command D1h  ... Enable Speaker
  15. ; ■ DSP command D3h  ... Disable Speaker
  16. ;
  17.  
  18. .MODEL small
  19. .286
  20.  
  21. ; CONSTANTS ───────────────────────────────────────────────────────────────────
  22.  
  23. ; SoundBlaster SETUP
  24. BASEADDR           EQU 0220h       ;SoundBlaster base address
  25. IRQ7               EQU 15          ;SoundBlaster IRQ
  26. DMAchannel         EQU 1           ;SoundBlaster DMA channel
  27.  
  28. ; PIC MASKS FOR MASK/DEMASK IRQ
  29. PICANDMASK         EQU 01111111b   ;'AND' PIC mask for clear IRQ7
  30. PICORMASK          EQU 10000000b   ;'OR' PIC mask for set IRQ7
  31.  
  32. ; DMA CONTROLLER REGISTERS :
  33. WRITEMASK          EQU 00ah         ;WRITE MASK REGISTER
  34. WRITEMODE          EQU 00bh         ;WRITE MODE REGISTER
  35. CLEARFLIPFLOP      EQU 00ch
  36. PAGE_CHN           EQU 083h         ;PAGE REGISTER FOR DMAchannel 1
  37. BASE_CHN           EQU 002h         ;BASEADDRESS REGISTER DMA 1
  38. COUNT_CHN          EQU 003h         ;COUNT REGISTER DMAchannel 1
  39.  
  40. ; SAMPLERATE : (if you change it pay attention to maximum samplerate)
  41. TIMECONST          EQU 165          ; = 10989 Hz (256-1000000/11000)
  42.  
  43. ; DMA WRITE MODE
  44. WANTEDMODE         EQU 01011000b    ; singlemode, autoinit, readmode
  45.  
  46.  
  47. ;──────────────────────────────────────────────────────────────────────────────
  48. ; MACRO DEFINITIONs
  49. ;──────────────────────────────────────────────────────────────────────────────
  50. STARTUP                 MACRO
  51. ; MASM 5.x COMPATIBILITY
  52. __start:                mov     ax,DGROUP
  53.                         mov     ds,ax
  54.                         mov     bx,ss
  55.                         sub     bx,ax
  56.                         shl     bx,004h
  57.                         mov     ss,ax
  58.                         add     sp,bx
  59. ENDM
  60.  
  61. WAITWRITE               MACRO
  62. LOCAL                   loopWait,endloop
  63. ;          Arguments : DX = Status port (BASEADDR+0Ch)
  64. ;          Returns   : n/a
  65. ;          Destroys  : AL
  66.  
  67.                         push    cx
  68.                         xor     cx,cx           ; need that for slow SBs !
  69. loopWait:               dec     cx
  70.                         jz      endloop
  71.                         in      al,dx           ; AL = WRITE COMMAND STATUS
  72.                         or      al,al
  73.                         js      loopWait        ; Jump if bit7=1 - writing not allowed
  74. endloop:                pop     cx
  75. ENDM
  76.  
  77. WAITREAD                MACRO
  78. LOCAL                   loopWait,endloop
  79. ;          Arguments : DX = Status port   (normaly BASEADDR+0Eh)
  80. ;          Returns   : n/a
  81. ;          Destroys  : AL
  82.  
  83.                         push    cx
  84.                         xor     cx,cx           ; need that for slow SBs !
  85. loopWait:               dec     cx
  86.                         jz      endloop
  87.                         in      al,dx           ; AL = DATA AVAILABLE STATUS
  88.                         or      al,al
  89.                         jns     loopWait        ; Jump if bit7=0 - no data available
  90. endloop:                pop     cx
  91. ENDM
  92.  
  93. RESET_DSP               MACRO
  94. local                   SBthere
  95. ;          Arguments : n/a
  96. ;          Returns   : n/a
  97. ;          Destroys  : DX,AL
  98.  
  99.                         mov      dx,BASEADDR+06h
  100.                         mov      al,1
  101.                         out      dx,al          ; start DSP reset
  102.  
  103.                         in       al,dx
  104.                         in       al,dx
  105.                         in       al,dx
  106.                         in       al,dx          ; wait 3 µsec
  107.  
  108.                         xor      al,al
  109.                         out      dx,al          ; end DSP Reset
  110.  
  111.                         add      dx,08h         ; dx = DSP DATA AVAILABLE
  112.                         WAITREAD
  113.                         sub      dx,4           ; dx = DSP Read Data
  114.                         in       al,dx
  115.                         cmp      al,0aah        ; if there is a SB then it returns 0AAh
  116.                         je       SBthere
  117.                         jmp      RESET_ERROR    ; No SB - exit program
  118. SBthere:
  119. ENDM
  120. ;─── End of Macrodefinitions ──────────────────────────────────────────────────
  121.  
  122. .STACK 100h
  123.  
  124. .DATA
  125. ;──────────────────────────────────────────────────────────────────────────────
  126. ; TWO COPIES FOR PAGE OVERRIDE REASONS :
  127.  
  128. SAMPLEBUFFER LABEL BYTE
  129.     INCLUDE TEST1.INC        ; FIRST COPY OF SAMPLE SOUND
  130. SAMPLEBUFFEREND LABEL BYTE
  131.     INCLUDE TEST1.INC        ; SECOND COPY OF SAMPLE SOUND
  132.  
  133.     part                db 1
  134.  
  135.     information         db 13,10,'DMASTEP3.EXE - repeat a 8bit mono sound again and again'
  136.                         db 13,10,'using autoinit mode (not highspeed) - hope you',39,'re not to bored ;)'
  137.                         db 13,10,'stop playing with <ESC> ...','$'
  138.     txtpart0            db 13,10,'playing part 0','$'
  139.     txtpart1            db 13,10,'playing part 1','$'
  140.     sberror             db 13,10,'No SoundBlaster at this BASEADDR ! PROGRAM HALTED.','$'
  141.  
  142.     OLDInterruptSEG     dw ?
  143.     OLDInterruptOFS     dw ?
  144.  
  145.     SAMPLEBUFFERLENGTH = offset SAMPLEBUFFEREND - offset SAMPLEBUFFER
  146. ;──────────────────────────────────────────────────────────────────────────────
  147. .CODE
  148.  STARTUP
  149.  
  150.            RESET_DSP
  151.  
  152.            ; WRITE INFORMATION TO SCREEN :
  153.            mov     dx,offset information
  154.            mov     ah,9
  155.            int     21h                         ; write program information to screen
  156.  
  157.            ; ENABLE SB SPEAKERS (for all SBs <SB16)
  158.            mov     dx,BASEADDR+00Ch            ;DX = DSP Write Data or Command
  159.            WAITWRITE
  160.            mov     al,0D1h                     ;AL = Enable speaker
  161.            out     dx,al                       ;   Output: DSP Write Data or Command
  162.  
  163.            ; SETUP IRQ :
  164.            xor     ax,ax
  165.            mov     es,ax                       ; es to page 0 (Interrupt table)
  166.            mov     si,IRQ7*4                   ; si = position in interrupt table
  167.  
  168.            ; DISABLE IRQ
  169.            in      al,021h
  170.            and     al,PICANDMASK               ; SET MASK REGISTER BIT TO DISABLE INTERRUPT
  171.            out     021h,al
  172.  
  173.            ; CHANGE POINTER IN INTERRUPT TABLE
  174.            mov     ax,es:[si]
  175.            mov     [OLDInterruptOFS],ax        ; save offset of old interupt vector for restoring
  176.            mov     ax,OFFSET OWN_IRQ
  177.            mov     es:[si],ax                  ; set offset of new interrupt routine
  178.            mov     ax,es:[si+2]
  179.            mov     [OLDInterruptSEG],ax        ; save segment of old interupt vector for restoring
  180.            mov     ax,cs
  181.            mov     es:[si+2],ax                ; set segment of new interrupt routine
  182.  
  183.            ; CHANGE PIC MASK :
  184.            in      al,021h
  185.            and     al,PICANDMASK   ; CLEAR MASK REGISTER BIT TO ENABLE INTERRUPT
  186.            out     021h,al
  187.  
  188. ;──────────────────────────────────────────────────────────────────────────────
  189. ; calculate page and offset for DMAcontroller :
  190. ;
  191. ; segment*16+offset - 20bit memory location -> upper 4 bits  = page
  192. ;                                              lower 16 bits = offset
  193. ;──────────────────────────────────────────────────────────────────────────────
  194.            mov     si,offset samplebuffer
  195.            mov     cx,SAMPLEBUFFERLENGTH-1
  196.  
  197.            mov     ax,ds
  198.            rol     ax,4                ; * 16 - higher 4 bits in al
  199.            mov     bl,al
  200.            and     bl,00fh             ; BL - higher 4 bits
  201.            and     al,0f0h             ; clear higher 4bits in AL
  202.            add     si,ax               ; SI = offset
  203.            adc     bl,0                ; BL = page
  204. ;──────────────────────────────────────────────────────────────────────────────
  205. ; check for DMApage override :
  206. ; ... problem: DMA controller separates memory into 64KB pages, you can only
  207. ; transfer data is placed in one page - no page overrides are allowed
  208. ;──────────────────────────────────────────────────────────────────────────────
  209. ; To solve that :
  210. ; creat a DMA buffer with double size you want - if the first part is placed
  211. ; on a page border the second part is for sure not
  212. ;──────────────────────────────────────────────────────────────────────────────
  213.            neg     si          ; si = 65536 - si   (bytes left to DMA page border)
  214.            cmp     si,cx       ; if si (bytes left to border) > cx (bytes to play)
  215.            ja      nooverride  ; then there's no page override
  216.  
  217.            ; WE HAVE TO USE SECOND PART
  218.            neg     si          ; si = offset of first part
  219.            add     si,cx       ; si = si + length of one part
  220.            inc     si          ; si=si+1 - start of second part
  221.            inc     bl          ; second part is then on the next page
  222.            neg     si          ; look at the next command ;)
  223.                                ; (that is better than a jump ?)
  224. nooverride:
  225.            neg     si
  226.  
  227. ;──────────────────────────────────────────────────────────────────────────────
  228. ; Setup DMA-controller :
  229. ;
  230. ; 1st  MASK DMA CHANNEL
  231. ;
  232.            mov     al,DMAchannel
  233.            add     al,4
  234.            out     WRITEMASK,al
  235. ;──────────────────────────────────────────────────────────────────────────────
  236. ; 2nd  CLEAR FLIPFLOP
  237. ;
  238.            out     CLEARFLIPFLOP,al
  239. ;──────────────────────────────────────────────────────────────────────────────
  240. ; 3rd  WRITE TRANSFER MODE
  241. ;
  242.            mov     al,WANTEDMODE
  243.            add     al,DMAchannel
  244.            out     WRITEMODE,al
  245. ;──────────────────────────────────────────────────────────────────────────────
  246. ; 4th  WRITE PAGE NUMBER
  247. ;
  248.            mov     al,bl
  249.            out     PAGE_CHN,al
  250. ;──────────────────────────────────────────────────────────────────────────────
  251. ; 5th  WRITE BASEADDRESS
  252. ;
  253.            mov     ax,si
  254.            out     BASE_CHN,al
  255.            mov     al,ah
  256.            out     BASE_CHN,al
  257. ;──────────────────────────────────────────────────────────────────────────────
  258. ; 6th  WRITE SAMPLELENGTH-1
  259. ;
  260.            mov     al,cl
  261.            out     COUNT_CHN,al
  262.            mov     al,ch
  263.            out     COUNT_CHN,al
  264. ;──────────────────────────────────────────────────────────────────────────────
  265. ; 7th  DEMASK CHANNEL
  266. ;
  267.            mov     al,DMAchannel
  268.            out     WRITEMASK,al
  269.  
  270. ;──────────────────────────────────────────────────────────────────────────────
  271. ; Setup SoundBlaster :
  272. ;
  273. ; 1st  SET TIMECONSTANTE
  274. ;
  275.            mov     dx,BASEADDR+00Ch            ;DX = DSP Write Data or Command
  276.            WAITWRITE
  277.            mov     al,040h                     ;AL = Set timeconstant
  278.            out     dx,al
  279.            WAITWRITE
  280.            mov     al,TIMECONST
  281.            out     dx,al
  282.  
  283. ;──────────────────────────────────────────────────────────────────────────────
  284. ; 2nd  use DMAplay 8bit mono autoinit (DSPcommand-01ch)
  285. ;
  286.            ; SETUP SIZE
  287.            WAITWRITE
  288.            mov     al,048h                     ;AL = DMA DAC 8bit
  289.            out     dx,al
  290.            mov     cx,SAMPLEBUFFERLENGTH
  291.            shr     cx,1                        ; generate IRQ every half buffer
  292.            dec     cx
  293.            WAITWRITE
  294.            mov     al,cl                       ;AL = LOWER PART SAMPLELENGTH
  295.            out     dx,al
  296.            WAITWRITE
  297.            mov     al,ch                       ;AL = HIGHER PART SAMPLELENGTH
  298.            out     dx,al
  299.  
  300.            ; SETUP PLAYMODE
  301.            WAITWRITE
  302.            mov     al,1ch                      ;AL = Auto-Initialize DMA DAC, 8-bit
  303.            out     dx,al
  304.  
  305. ; TRANSFER STARTS ....... NOW ..... :)
  306.  
  307. waitloop:
  308.            mov     ah,01                       ;AH = Check for character function
  309.            int     016h                        ;   Interrupt: Keyboard
  310.            jz      waitloop
  311.            xor     ah,ah
  312.            int     016h
  313.            cmp     al,27                       ; wait for <ESC>
  314.            jne     waitloop
  315.  
  316.            ; RESET SOUNDBLASTER
  317.            RESET_DSP
  318.  
  319. exit:      ; RESTORE PIC MASK
  320.            in      al,021h
  321.            or      al,PICORMASK                ;<-- SET REGISTER MASK BITS TO DISABLE
  322.            out     021h,al
  323.  
  324.            ; RESTORE IRQ :
  325.            xor     ax,ax
  326.            mov     es,ax                       ; es to page 0 (Interrupt table)
  327.            mov     si,IRQ7*4
  328.            mov     ax,[OLDInterruptOFS]
  329.            mov     es:[si],ax                  ; set old interrupt routine
  330.            mov     ax,[OLDInterruptSEG]
  331.            mov     es:[si+2],ax
  332.  
  333.            ; CLEAR KEYBUFFER
  334.            mov     ah,01                       ;AH = Check for character function
  335.            int     16h                         ;   Interrupt: Keyboard
  336.            jz      return2dos
  337.            xor     ah,ah                       ;Read character, flush keypress
  338.            int     016h                        ;   Interrupt: Keyboard
  339.  
  340.            ; TERMINATE EXE:
  341. return2dos:
  342.            mov     ax,04c00h
  343.            int     21h
  344.  
  345. ; display information if Soundblaster is not on this baseaddress
  346. RESET_ERROR:
  347.            mov     dx,offset sberror
  348.            mov     ah,9
  349.            int     21h                         ; text output
  350.            jmp     return2dos
  351.  
  352. ;──────────────────────────────────────────────────────────────────────────────
  353. ; Our own IRQ for detecting buffer half SB currently plays
  354. ; It's generated by the SoundBlaster hardware
  355. ;──────────────────────────────────────────────────────────────────────────────
  356. OWN_IRQ:
  357.            pusha
  358.            mov     dx,BASEADDR+00Eh            ;DX = DSP DATA AVAILABLE (IRQ ACKNOWLEDGE)
  359.            in      al,dx
  360.            mov     ax,@data
  361.            mov     ds,ax
  362.            mov     dx,offset txtpart0
  363.            cmp     [part],0
  364.            je      notpart1
  365.            mov     dx,offset txtpart1
  366. notpart1:
  367.            mov     ah,9
  368.            int     21h             ; text output
  369.            neg     [part]
  370.            inc     [part]          ; part = 1-part  result : 0,1,0,1,0,....
  371.            mov     al,020h
  372.            out     020h,al                     ;ACKNOWLEDGE HARDWARE INTERRUPT
  373.            popa
  374.            IRET
  375.  
  376. END     __start
  377.